﻿package systems.traer
{
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.display.Sprite;
	import flash.display.TriangleCulling;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.filters.BlurFilter;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	import utils.GeomUtils;
	
	public class ClothImage extends Sprite 
	{
		
		private var physics:ParticleSystem;
		private var particles:Vector.<Vector.<Particle>>;
		private var gridWidth:int = 15;
		private var gridHeight:int = 15;
		
		private const SPRING_STRENGTH:Number = .11;
		private const SPRING_DAMPING:Number = 0.2;
		
		private var isDown:Boolean = false;
		private var old:Point = new Point();
		private var corners:Vector.<Particle>;
		private var srcBd:BitmapData = new BitmapData( 400,400, true,0 );
		private var indices:Vector.<int>;
		private var uvs:Vector.<Number>;
		
		public function ClothImage():void 
		{
			
			//stage.frameRate = 42;
			srcBd.perlinNoise( 20, 100, 3, 0, true, true, 1, true );
			srcBd.copyChannel( srcBd, srcBd.rect, new Point(), BitmapDataChannel.RED, BitmapDataChannel.ALPHA );
			//srcBd.applyFilter( srcBd, srcBd.rect, new Point(), new BlurFilter( 12, 12, 3 ) );
			
			srcBd.threshold( srcBd, srcBd.rect, new Point(), '>=', 0x80000000, 0 );
			srcBd.threshold( srcBd, srcBd.rect, new Point(), '!=', 0, 0xFFFFFFFF );
			
			physics = new ParticleSystem( new Vector3D( 0, 0.1, 0 ), 0.01 );
			
			particles = new Vector.<Vector.<Particle>>( gridHeight, true);
			
			var gridStepX:Number = (stage.stageWidth / 2) / gridWidth;
			var gridStepY:Number = (stage.stageHeight / 2) / gridHeight;
			
			
			var left:Number = stage.stageWidth / 2 - ( ( gridStepX * gridWidth ) / 2 );
			var top:Number = stage.stageHeight / 2 - ( ( gridStepY * gridHeight ) / 2 );
			
			uvs 		= new Vector.<Number>();
			indices 		= new Vector.<int>();
			
			
			var i:int, j:int, k:int= 0;
			
			for (i = 0; i < gridHeight; i++) 
			{
				
				particles[i] = new Vector.<Particle>( gridWidth, true);
				
				for (j = 0; j < gridWidth; j++) 
				{
					
					particles[ i ][ j ] = physics.makeParticle( 1, left + i * gridStepX,  top + j * gridStepY  );
					particles[ i ][ j ].id = k;
					k++;
					if( i > 0 ) physics.makeSpring(particles[i - 1][j], particles[i][j], SPRING_STRENGTH, SPRING_DAMPING, gridStepX);
					if( j > 0 ) physics.makeSpring(particles[i][j - 1], particles[i][j], SPRING_STRENGTH, SPRING_DAMPING, gridStepY);
					
					uvs.push( j / gridWidth, i / gridHeight );
					
				}
			}
			
			k = 0;
			for ( i = 0; i < gridHeight - 1; i++ )
			{
				for ( j = 0; j < gridWidth - 1; j++ )
				{
					k = i * gridHeight + j;
					indices.push( k, k + 1, ( k + gridWidth )  );
					indices.push( k + 1, ( k + gridWidth ) + 1, ( k + gridWidth )  );
				}
			}
			
			corners = Vector.<Particle>( 	[
											particles[ 0 ][ 0 ], 
											particles[ 0 ][ gridWidth - 1 ],
											particles[ gridHeight - 1 ][ 0 ], 
											particles[ gridHeight - 1 ][ gridWidth - 1] 
											] );
											
			for each( var p:Particle in corners )
			{
				p.fixed = true;
			}
			
			stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
			addEventListener(Event.ENTER_FRAME, draw);
			
		}
		
		
		private function onDown(e:MouseEvent):void 
		{
			isDown = true;
		}
		
		private function onUp(e:MouseEvent):void
		{
			isDown = false;
		}
		
		private function draw(e:Event = null):void
		{
			
			physics.tick();
			var p:Particle;
			
			if (isDown)
			{
				p = getClosestParticle();
				p.position.x = mouseX;
				p.position.y = mouseY;
				p.clearVelocity();
			}
			
			graphics.clear();
			
			var i:int, j:int, i0:int, i1:int, i2:int, i3:int;
			var v:Vector3D;
			
			var vertices:Vector.<Number> 	= new Vector.<Number>();
			
			for (i = 0; i < gridHeight; i++)
			{
				for (j = 0; j < gridWidth; j++)
				{
					
					v = particles[ i ][ j ].position;
					vertices.push( v.x, v.y );
					    
				}
			}
			
			graphics.beginBitmapFill( srcBd, null, true, true );
			graphics.drawTriangles( vertices, indices, uvs, TriangleCulling.NONE );
			
			old.x = mouseX;
			old.y = mouseY;
			
		}
		
		private function getClosestParticle():Particle 
		{
			var distMax:Number = Number.POSITIVE_INFINITY;
			var dist:Number;
			var _p:Particle;
			for each( var p:Particle in corners )
			{
				dist = GeomUtils.distance( new Point( p.position.x, p.position.y ), new Point( mouseX, mouseY ) );
				if ( dist < distMax )
				{
					distMax = dist;
					_p = p;
				}
			}
			return _p;
		}
		
		
	}
	
}